home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 5 / Apprentice-Release5.iso / Source Code / C / Applications / Python 1.3.3 / Python 133 SRC / Demo / tkinter / guido / AttrDialog.py next >
Text File  |  1995-12-21  |  11KB  |  464 lines

  1.  
  2. # The options of a widget are described by the following attributes
  3. # of the Pack and Widget dialogs:
  4. #
  5. # Dialog.current: {name: value}
  6. # -- changes during Widget's lifetime
  7. #
  8. # Dialog.options: {name: (default, klass)}
  9. # -- depends on widget class only
  10. #
  11. # Dialog.classes: {klass: (v0, v1, v2, ...) | 'boolean' | 'other'}
  12. # -- totally static, though different between PackDialog and WidgetDialog
  13. #    (but even that could be unified)
  14.  
  15. from Tkinter import *
  16.  
  17. class Option:
  18.  
  19.     varclass = StringVar        # May be overridden
  20.  
  21.     def __init__(self, dialog, option):
  22.         self.dialog = dialog
  23.         self.option = option
  24.         self.master = dialog.top
  25.         self.default, self.klass = dialog.options[option]
  26.         self.var = self.varclass(self.master)
  27.         self.frame = Frame(self.master,
  28.                    {Pack: {'expand': 0, 'fill': 'x'}})
  29.         self.label = Label(self.frame,
  30.                    {'text': option + ':',
  31.                     Pack: {'side': 'left'},
  32.                     })
  33.         self.update()
  34.         self.addoption()
  35.  
  36.     def refresh(self):
  37.         self.dialog.refresh()
  38.         self.update()
  39.  
  40.     def update(self):
  41.         try:
  42.             self.current = self.dialog.current[self.option]
  43.         except KeyError:
  44.             self.current = self.default
  45.         self.var.set(self.current)
  46.  
  47.     def set(self, e=None):        # Should be overridden
  48.         pass
  49.  
  50. class BooleanOption(Option):
  51.  
  52.     varclass = BooleanVar
  53.  
  54.     def addoption(self):
  55.         self.button = Checkbutton(self.frame,
  56.                      {'text': 'on/off',
  57.                       'onvalue': '1',
  58.                       'offvalue': '0',
  59.                       'variable': self.var,
  60.                       'relief': 'raised',
  61.                       'borderwidth': 2,
  62.                       'command': self.set,
  63.                       Pack: {'side': 'right'},
  64.                       })
  65.  
  66. class EnumOption(Option):
  67.  
  68.     def addoption(self):
  69.         self.button = Menubutton(self.frame,
  70.                      {'textvariable': self.var,
  71.                       'relief': 'raised',
  72.                       'borderwidth': 2,
  73.                       Pack: {'side': 'right'},
  74.                       })
  75.         self.menu = Menu(self.button)
  76.         self.button['menu'] = self.menu
  77.         for v in self.dialog.classes[self.klass]:
  78.             self.menu.add_radiobutton(
  79.                 {'label': v,
  80.                  'variable': self.var,
  81.                  'value': v,
  82.                  'command': self.set,
  83.                  })
  84.  
  85. class StringOption(Option):
  86.  
  87.     def addoption(self):
  88.         self.entry = Entry(self.frame,
  89.                    {'textvariable': self.var,
  90.                     'width': 10,
  91.                     'relief': 'sunken',
  92.                     'borderwidth': 2,
  93.                     Pack: {'side': 'right',
  94.                        'fill': 'x', 'expand': 1},
  95.                     })
  96.         self.entry.bind('<Return>', self.set)
  97.  
  98. class ReadonlyOption(Option):
  99.  
  100.     def addoption(self):
  101.         self.label = Label(self.frame,
  102.                    {'textvariable': self.var,
  103.                     'anchor': 'e',
  104.                     Pack: {'side': 'right'}})
  105.  
  106. class Dialog:
  107.  
  108.     def __init__(self, master):
  109.         self.master = master
  110.         self.fixclasses()
  111.         self.refresh()
  112.         self.top = Toplevel(self.master)
  113.         self.top.title(self.__class__.__name__)
  114.         self.top.minsize(1, 1)
  115.         self.addchoices()
  116.  
  117.     def refresh(self): pass        # Must override
  118.  
  119.     def fixclasses(self): pass    # May override
  120.  
  121.     def addchoices(self):
  122.         self.choices = {}
  123.         list = []
  124.         for k, dc in self.options.items():
  125.             list.append(k, dc)
  126.         list.sort()
  127.         for k, (d, c) in list:
  128.             try:
  129.                 cl = self.classes[c]
  130.             except KeyError:
  131.                 cl = 'unknown'
  132.             if type(cl) == TupleType:
  133.                 cl = self.enumoption
  134.             elif cl == 'boolean':
  135.                 cl = self.booleanoption
  136.             elif cl == 'readonly':
  137.                 cl = self.readonlyoption
  138.             else:
  139.                 cl = self.stringoption
  140.             self.choices[k] = cl(self, k)
  141.  
  142.     # Must override:
  143.     options = {}
  144.     classes = {}
  145.  
  146.     # May override:
  147.     booleanoption = BooleanOption
  148.     stringoption = StringOption
  149.     enumoption = EnumOption
  150.     readonlyoption = ReadonlyOption
  151.  
  152. class PackDialog(Dialog):
  153.  
  154.     def __init__(self, widget):
  155.         self.widget = widget
  156.         Dialog.__init__(self, widget)
  157.  
  158.     def refresh(self):
  159.         self.current = self.widget.newinfo()
  160.         self.current['.class'] = self.widget.winfo_class()
  161.         self.current['.name'] = self.widget._w
  162.  
  163.     class packoption: # Mix-in class
  164.         def set(self, e=None):
  165.             self.current = self.var.get()
  166.             try:
  167.                 Pack.config(self.dialog.widget,
  168.                         {self.option: self.current})
  169.             except TclError, msg:
  170.                 print msg
  171.                 self.refresh()
  172.  
  173.     class booleanoption(packoption, BooleanOption): pass
  174.     class enumoption(packoption, EnumOption): pass
  175.     class stringoption(packoption, StringOption): pass
  176.     class readonlyoption(packoption, ReadonlyOption): pass
  177.  
  178.     options = {
  179.         '.class': (None, 'Class'),
  180.         '.name': (None, 'Name'),
  181.         'after': (None, 'Widget'),
  182.         'anchor': ('center', 'Anchor'),
  183.         'before': (None, 'Widget'),
  184.         'expand': ('no', 'Boolean'),
  185.         'fill': ('none', 'Fill'),
  186.         'in': (None, 'Widget'),
  187.         'ipadx': (0, 'Pad'),
  188.         'ipady': (0, 'Pad'),
  189.         'padx': (0, 'Pad'),
  190.         'pady': (0, 'Pad'),
  191.         'side': ('top', 'Side'),
  192.         }
  193.  
  194.     classes = {
  195.         'Anchor': ('n','ne', 'e','se', 's','sw', 'w','nw', 'center'),
  196.         'Boolean': 'boolean',
  197.         'Class': 'readonly',
  198.         'Expand': 'boolean',
  199.         'Fill': ('none', 'x', 'y', 'both'),
  200.         'Name': 'readonly',
  201.         'Pad': 'pixel',
  202.         'Side': ('top', 'right', 'bottom', 'left'),
  203.         'Widget': 'readonly',
  204.         }
  205.  
  206. class RemotePackDialog(PackDialog):
  207.  
  208.     def __init__(self, master, app, widget):
  209.         self.master = master
  210.         self.app = app
  211.         self.widget = widget
  212.         self.refresh()
  213.         self.top = Toplevel(self.master)
  214.         self.top.title(self.app + ' PackDialog')
  215.         self.top.minsize(1, 1)
  216.         self.addchoices()
  217.  
  218.     def refresh(self):
  219.         try:
  220.             words = self.master.tk.splitlist(
  221.                 self.master.send(self.app,
  222.                          'pack',
  223.                          'newinfo',
  224.                          self.widget))
  225.         except TclError, msg:
  226.             print msg
  227.             return
  228.         dict = {}
  229.         for i in range(0, len(words), 2):
  230.             key = words[i][1:]
  231.             value = words[i+1]
  232.             dict[key] = value
  233.         dict['.class'] = self.master.send(self.app,
  234.                           'winfo',
  235.                           'class',
  236.                           self.widget)
  237.         dict['.name'] = self.widget
  238.         self.current = dict
  239.  
  240.     class remotepackoption: # Mix-in class
  241.         def set(self, e=None):
  242.             self.current = self.var.get()
  243.             try:
  244.                 self.dialog.master.send(
  245.                     self.dialog.app,
  246.                     'pack',
  247.                     'config',
  248.                     self.dialog.widget,
  249.                     '-'+self.option,
  250.                     self.dialog.master.tk.merge(
  251.                         self.current))
  252.             except TclError, msg:
  253.                 print msg
  254.                 self.refresh()
  255.  
  256.     class booleanoption(remotepackoption, BooleanOption): pass
  257.     class enumoption(remotepackoption, EnumOption): pass
  258.     class stringoption(remotepackoption, StringOption): pass
  259.     class readonlyoption(remotepackoption, ReadonlyOption): pass
  260.  
  261. class WidgetDialog(Dialog):
  262.  
  263.     def __init__(self, widget):
  264.         self.widget = widget
  265.         self.klass = widget.winfo_class()
  266.         Dialog.__init__(self, widget)
  267.  
  268.     def fixclasses(self):
  269.         if self.addclasses.has_key(self.klass):
  270.             classes = {}
  271.             for c in (self.classes,
  272.                   self.addclasses[self.klass]):
  273.                 for k in c.keys():
  274.                     classes[k] = c[k]
  275.             self.classes = classes
  276.  
  277.     def refresh(self):
  278.         self.configuration = self.widget.config()
  279.         self.update()
  280.         self.current['.class'] = self.widget.winfo_class()
  281.         self.current['.name'] = self.widget._w
  282.  
  283.     def update(self):
  284.         self.current = {}
  285.         self.options = {}
  286.         for k, v in self.configuration.items():
  287.             if len(v) > 4:
  288.                 self.current[k] = v[4]
  289.                 self.options[k] = v[3], v[2] # default, klass
  290.         self.options['.class'] = (None, 'Class')
  291.         self.options['.name'] = (None, 'Name')
  292.  
  293.     class widgetoption: # Mix-in class
  294.         def set(self, e=None):
  295.             self.current = self.var.get()
  296.             try:
  297.                 self.dialog.widget[self.option] = self.current
  298.             except TclError, msg:
  299.                 print msg
  300.                 self.refresh()
  301.  
  302.     class booleanoption(widgetoption, BooleanOption): pass
  303.     class enumoption(widgetoption, EnumOption): pass
  304.     class stringoption(widgetoption, StringOption): pass
  305.     class readonlyoption(widgetoption, ReadonlyOption): pass
  306.  
  307.     # Universal classes
  308.     classes = {
  309.         'Anchor': ('n','ne', 'e','se', 's','sw', 'w','nw', 'center'),
  310.         'Aspect': 'integer',
  311.         'Background': 'color',
  312.         'Bitmap': 'bitmap',
  313.         'BorderWidth': 'pixel',
  314.         'Class': 'readonly',
  315.         'CloseEnough': 'double',
  316.         'Command': 'command',
  317.         'Confine': 'boolean',
  318.         'Cursor': 'cursor',
  319.         'CursorWidth': 'pixel',
  320.         'DisabledForeground': 'color',
  321.         'ExportSelection': 'boolean',
  322.         'Font': 'font',
  323.         'Foreground': 'color',
  324.         'From': 'integer',
  325.         'Geometry': 'geometry',
  326.         'Height': 'pixel',
  327.         'InsertWidth': 'time',
  328.         'Justify': ('left', 'center', 'right'),
  329.         'Label': 'string',
  330.         'Length': 'pixel',
  331.         'MenuName': 'widget',
  332.         'Name': 'readonly',
  333.         'OffTime': 'time',
  334.         'OnTime': 'time',
  335.         'Orient': ('horizontal', 'vertical'),
  336.         'Pad': 'pixel',
  337.         'Relief': ('raised', 'sunken', 'flat', 'ridge', 'groove'),
  338.         'RepeatDelay': 'time',
  339.         'RepeatInterval': 'time',
  340.         'ScrollCommand': 'command',
  341.         'ScrollIncrement': 'pixel',
  342.         'ScrollRegion': 'rectangle',
  343.         'ShowValue': 'boolean',
  344.         'SetGrid': 'boolean',
  345.         'Sliderforeground': 'color',
  346.         'SliderLength': 'pixel',
  347.         'Text': 'string',
  348.         'TickInterval': 'integer',
  349.         'To': 'integer',
  350.         'Underline': 'index',
  351.         'Variable': 'variable',
  352.         'Value': 'string',
  353.         'Width': 'pixel',
  354.         'Wrap': ('none', 'char', 'word'),
  355.         }
  356.  
  357.     # Classes that (may) differ per widget type
  358.     _tristate = {'State': ('normal', 'active', 'disabled')}
  359.     _bistate = {'State': ('normal', 'disabled')}
  360.     addclasses = {
  361.         'Button': _tristate,
  362.         'Radiobutton': _tristate,
  363.         'Checkbutton': _tristate,
  364.         'Entry': _bistate,
  365.         'Text': _bistate,
  366.         'Menubutton': _tristate,
  367.         'Slider': _bistate,
  368.         }
  369.  
  370. class RemoteWidgetDialog(WidgetDialog):
  371.  
  372.     def __init__(self, master, app, widget):
  373.         self.app = app
  374.         self.widget = widget
  375.         self.klass = master.send(self.app,
  376.                      'winfo',
  377.                      'class',
  378.                      self.widget)
  379.         Dialog.__init__(self, master)
  380.  
  381.     def refresh(self):
  382.         try:
  383.             items = self.master.tk.splitlist(
  384.                 self.master.send(self.app,
  385.                          self.widget,
  386.                          'config'))
  387.         except TclError, msg:
  388.             print msg
  389.             return
  390.         dict = {}
  391.         for item in items:
  392.             words = self.master.tk.splitlist(item)
  393.             key = words[0][1:]
  394.             value = (key,) + words[1:]
  395.             dict[key] = value
  396.         self.configuration = dict
  397.         self.update()
  398.         self.current['.class'] = self.klass
  399.         self.current['.name'] = self.widget
  400.  
  401.     class remotewidgetoption: # Mix-in class
  402.         def set(self, e=None):
  403.             self.current = self.var.get()
  404.             try:
  405.                 self.dialog.master.send(
  406.                     self.dialog.app,
  407.                     self.dialog.widget,
  408.                     'config',
  409.                     '-'+self.option,
  410.                     self.current)
  411.             except TclError, msg:
  412.                 print msg
  413.                 self.refresh()
  414.  
  415.     class booleanoption(remotewidgetoption, BooleanOption): pass
  416.     class enumoption(remotewidgetoption, EnumOption): pass
  417.     class stringoption(remotewidgetoption, StringOption): pass
  418.     class readonlyoption(remotewidgetoption, ReadonlyOption): pass
  419.  
  420. def test():
  421.     import sys
  422.     root = Tk()
  423.     root.minsize(1, 1)
  424.     if sys.argv[1:]:
  425.         remotetest(root, sys.argv[1])
  426.     else:
  427.         frame = Frame(root, {'name': 'frame',
  428.                      Pack: {'expand': 1, 'fill': 'both'},
  429.                      })
  430.         button = Button(frame, {'name': 'button',
  431.                     'text': 'button',
  432.                     Pack: {'expand': 1}})
  433.         canvas = Canvas(frame, {'name': 'canvas',
  434.                     Pack: {}})
  435.         fpd = PackDialog(frame)
  436.         fwd = WidgetDialog(frame)
  437.         bpd = PackDialog(button)
  438.         bwd = WidgetDialog(button)
  439.         cpd = PackDialog(canvas)
  440.         cwd = WidgetDialog(canvas)
  441.     root.mainloop()
  442.  
  443. def remotetest(root, app):
  444.     from listtree import listtree
  445.     list = listtree(root, app)
  446.     list.bind('<Any-Double-1>', opendialogs)
  447.     list.app = app            # Pass it on to handler
  448.  
  449. def opendialogs(e):
  450.     import string
  451.     list = e.widget
  452.     sel = list.curselection()
  453.     for i in sel:
  454.         item = list.get(i)
  455.         widget = string.split(item)[0]
  456.         RemoteWidgetDialog(list, list.app, widget)
  457.         if widget == '.': continue
  458.         try:
  459.             RemotePackDialog(list, list.app, widget)
  460.         except TclError, msg:
  461.             print msg
  462.  
  463. test()
  464.